/**
 * 
 */
package dms.repository.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.Transaction;

import dms.model.Building;
import dms.model.Campus;
import dms.model.form.Bulletin;
import dms.model.form.Notice;
import dms.model.util.FindUtil;
import dms.model.util.PageIterator;
import dms.repository.BulletinRepository;
import dms.util.HibernateUtil;

/**
 * @author 李健
 *
 */
public class BulletinRepositoryHibernate implements BulletinRepository {

	private static final Log log = LogFactory.getLog(BulletinRepositoryHibernate.class);
	
	/* (non-Javadoc)
	 * @see dms.repository.BulletinRepository#createBulletin(dms.model.form.Bulletin)
	 */
	@Override
	public Bulletin createBulletin(Bulletin bulletin) throws Exception {
		Session session = null;
		Transaction tx = null;
		
		try {
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			session.save(bulletin);
			
			tx.commit();
		} catch (Exception e) {
			log.error(e.getMessage());
			if (tx != null) {
				tx.rollback();
			}
			throw e;
			
		} finally {
			if (session != null) {
				if (session.isOpen()) {
					session.close();
				}
			}
		}
		return bulletin;
	}

	/* (non-Javadoc)
	 * @see dms.repository.BulletinRepository#deleteBulletinById(java.lang.Long)
	 */
	@Override
	public void deleteBulletinById(Long id) throws Exception {
		Session session = null;
		Transaction tx = null;
		
		try {
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			Bulletin bulletin = (Bulletin) session.load(Bulletin.class, id);
			session.delete(bulletin);
			
			tx.commit();
		} catch (Exception e) {
			log.error(e.getMessage());
			if (tx != null) {
				tx.rollback();
			}
			throw e;
			
		} finally {
			if (session != null) {
				if (session.isOpen()) {
					session.close();
				}
			}
		}
	}

	/* (non-Javadoc)
	 * @see dms.repository.BulletinRepository#deleteBulletins(java.util.List)
	 */
	@Override
	public void deleteBulletins(List<Long> ids) throws Exception {
		Session session = null;
		Transaction tx = null;
		
		String deleteQuery = "delete from Bulletin b where b.id in (:ids)";
		
		try {
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			session.createQuery(deleteQuery)
				   .setParameterList("ids", ids)
				   .executeUpdate();
			
			tx.commit();
		} catch (Exception e) {
			log.error(e.getMessage());
			if (tx != null) {
				tx.rollback();
			}
			throw e;
			
		} finally {
			if (session != null) {
				if (session.isOpen()) {
					session.close();
				}
			}
		}

	}

	/* (non-Javadoc)
	 * @see dms.repository.BulletinRepository#deleteBulletins(java.lang.Long[])
	 */
	@Override
	public void deleteBulletins(Long[] ids) throws Exception {
		deleteBulletins(Arrays.asList(ids));

	}

	/* (non-Javadoc)
	 * @see dms.repository.BulletinRepository#findAll(int, int, java.util.Date, java.util.Date, java.lang.String)
	 */
	@Override
	public PageIterator<Bulletin> findAll(int start, int count, Date fromDate,
			Date toDate, String query) {
		return find(start, count, fromDate, toDate, null, query);
	}

	/* (non-Javadoc)
	 * @see dms.repository.BulletinRepository#findByBuilding(int, int, java.util.Date, java.util.Date, dms.model.Building, java.lang.String)
	 */
	@Override
	public PageIterator<Bulletin> findByBuilding(int start, int count,
			Date fromDate, Date toDate, Building building, String query) {
		Map keyValue = new HashMap();
		keyValue.put("building", building);
		return find(start, count, fromDate, toDate, keyValue, query);
	}

	/* (non-Javadoc)
	 * @see dms.repository.BulletinRepository#findByCampus(int, int, java.util.Date, java.util.Date, dms.model.Campus, java.lang.String)
	 */
	@Override
	public PageIterator<Bulletin> findByCampus(int start, int count,
			Date fromDate, Date toDate, Campus campus, String query) {
		Map keyValue = new HashMap();
		keyValue.put("building.campus", campus);
		return find(start, count, fromDate, toDate, keyValue, query);
	}

	/* (non-Javadoc)
	 * @see dms.repository.BulletinRepository#updateBulletin(dms.model.form.Bulletin)
	 */
	@Override
	public Bulletin updateBulletin(Bulletin bulletin) throws Exception {
		Session session = null;
		Transaction tx = null;
		
		Bulletin b = null;
		try {
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			bulletin = (Bulletin) session.merge(bulletin);
			
			tx.commit();
		} catch (Exception e) {
			log.error(e.getMessage());
			if (tx != null) {
				tx.rollback();
			}
			throw e;
			
		} finally {
			if (session != null) {
				if (session.isOpen()) {
					session.close();
				}
			}
		}
		return b;
	}
	
	/**
	 * 产生HQL的helper method
	 * @param start
	 * @param count
	 * @param fromDate
	 * @param toDate
	 * @param keyVlaue
	 * @return Object[0] = countQuery, Object[1] = findQuery, Object[2] = params : List
	 */
	private Object[] makeHQLQuery(Date fromDate, Date toDate, Map keyValue, String query) {
		
		
		StringBuilder countQuery = new StringBuilder("select count(*) from Bulletin b where");
		StringBuilder findQuery = new StringBuilder("select b from Bulletin b  where");
		StringBuilder conditionQuery = new StringBuilder();				
		
		Collection params = new ArrayList();;
				
		if (keyValue != null) {
		
			Set set = keyValue.entrySet();
			Iterator keyIter = set.iterator();
		
			while (keyIter.hasNext()) {
				Map.Entry<String, Object> entry = (Entry<String, Object>) keyIter
						.next();
				String name = entry.getKey();
				Object value = entry.getValue();

				conditionQuery.append(" b." + name + " = ? and ");
				params.add(value);
			}
		}
		if (fromDate != null && toDate == null) {
			conditionQuery.append(" b.publishDate >= ?  and ");
			params.add(fromDate);
		}
		if (fromDate == null && toDate != null) {
			conditionQuery.append(" b.publishDate <= ?  and ");
			params.add(toDate);
		}
		if (fromDate != null && toDate != null) {
			conditionQuery.append(" (b.publishDate between ? and ?)  and ");
			params.add(fromDate);
			params.add(toDate);
		}
		
		if (query != null) {
			conditionQuery.append(" ( b.title like ? or b.content like ? ) and ");
			params.add("%" + query + "%");
			params.add("%" + query + "%");
		}
		
		conditionQuery.append(" b.id = b.id ");
		countQuery.append(conditionQuery);
		findQuery.append(conditionQuery);
		
		return new Object[]{countQuery.toString(), findQuery.toString(), params};
	}
	
	private PageIterator<Bulletin> find(int start, int count, Date fromDate, Date toDate, Map keyValue, String query) {
		Object[] queries = makeHQLQuery(fromDate, toDate, keyValue, query);
		String countQuery = (String) queries[0];
		String findQuery = (String) queries[1];
		Collection params = (Collection) queries[2];
		
		Session session = null;
		Transaction tx = null;
		
		List<Bulletin> list = null;
		PageIterator<Bulletin> iter = null;
		Long allCount = null;
		
		try {
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			allCount = FindUtil.calculateAllCount(session, countQuery, params);
			list = FindUtil.getEntitiesByPage(session, findQuery, params, start, count);
			iter = new PageIterator<Bulletin>(list, allCount, start, count);
			
			tx.commit();
		} catch (Exception e) {
			log.error(e.getMessage());
			if (tx != null) {
				tx.rollback();
			}
			
		} finally {
			if (session != null) {
				if (session.isOpen()) {
					session.close();
				}
			}
		}
		
		return iter;
	}

	@Override
	public Bulletin findById(Long id) {
		Session session = null;
		Transaction tx = null;
		
		Bulletin b = null;
		try {
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			b = (Bulletin) session.get(Bulletin.class, id);
			
			tx.commit();
		} catch (Exception e) {
			log.error(e.getMessage());
			if (tx != null) {
				tx.rollback();
			}		
			
		} finally {
			if (session != null) {
				if (session.isOpen()) {
					session.close();
				}
			}
		}
		return b;
	}
	

}
